Function.prototype.myCall = function (context, ...args) {
  // 思路: 让context可以执行该函数,转变为给context添加该函数,运行后删除即可
  var context = context || window;
  // getValue.call(obj, 'bufan');
  context.fn = this; // this指向调用者 也就是该函数
  var result = context.fn(...args);
  delete context.fn;
  return result;
};

Function.prototype.myApply = function (context, args) {
  var context = context || window;
  context.fn = this;
  // 后续参数
  var result;
  if (args) {
    result = context.fn(...args);
  } else {
    result = context.fn();
  }
  delete context.fn;
  return result;
};

// 会创建一个新函数。
// 当这个新函数被调用时，bind() 的第一个参数将作为它运行时的 this，
// 之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN )
Function.prototype.myBind = function (context, ...args) {
  if (typeof this !== "function") {
    throw new TypeError("error");
  }
  var _this = this;
  // 参数

  // 返回一个函数
  return function F() {
    // 所以需要判断 new F()
    // 在构造器内
    // instanceof 可以判断 F 是作为构造器使用(true)  还是  普通函数使用(false)
    if (this instanceof F) {
      return new _this(...args, ...arguments);
    } else {
      return _this.apply(context, args.concat(...arguments));
    }
  };
};

// new 操作
// 它创建了一个全新的对象。
// 它会被执行[[Prototype]]（也就是__proto__）链接。
// 它使this指向新创建的对象。。
// 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。
// 如果函数没有返回对象类型Object(包含Functoin, Array, Date, RegExg, Error)，
// 那么new表达式中的函数调用将返回该对象引用。

function myNew(fn) {
  var obj = {};
  if (fn.prototype !== null) {
    obj.__proto__ = fn.prototype;
  }
  // var args = [...arguments].slice(1);
  // 将 this 指向 obj
  var result = fn.apply(obj, Array.prototype.slice(arguments, 1));
  return result instanceof Object ? result : obj;
}

Function.prototype.myCall = function (context) {
  const context = context || window;
  context.fn = this;
  let args = [...arguments].slice(1);

  let result = context.fn(...args);
  delete context.fn;
  return result;
};

Function.prototype.myApply = function (context) {
  const context = context || window;
  context.fn = this;
  let args = arguments[1];
  let result = context.fn(...args);
  return result;
};

Function.prototype.myBind = function (context) {
  const that = this;
  let args = [...arguments].slice(1);
  return function F() {
    if (this instanceof F) {
      return new that(...args, ...arguments);
    } else {
      that.apply(context, args.concat([...arguments]));
    }
  };
};

function myNew() {
  let obj = {};
  if (fn.prototype != null) {
    obj.__proto__ = fn.prototype;
  }
  let args = [...arguments].slice(1);
  let result = fn.apply(obj, args);
  return result instanceof Object ? result : obj;
}

function myIns(left, right) {
  while (true) {
    left = left.__proto__;
    if (left === null || left === undefined) {
      return false;
    }
    if (left === right.prototype) {
      return true;
    }
  }
}
